<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>

</body>
<script>
  window.external.upload = function (state) {
    console.log(state);
  }

  let plugin = (function () {
    let plugin = document.createElement("embed");
    plugin.style.display = "none";

    plugin.type = "application/txftn-webkit";

    plugin.sign = function () {
      console.log("开始扫描文件");
    };

    plugin.pause = function () {
      console.log("暂停文件上传");
    };

    plugin.uploading = function () {
      console.log("开始文件上传");
    };

    plugin.del = function () {
      console.log("删除文件上传");
    };

    plugin.done = function () {
      console.log("文件上传完成");
    };

    document.body.appendChild(plugin);
    return plugin;
  })();

  class Upload {
    constructor(fileName) {
      this.plugin = plugin;
      this.fileName = fileName;
      this.button1 = null;
      this.button2 = null;
      this.signState = new SignState(this);
      this.uploadingState = new UploadingState(this);
      this.pauseState = new PauseState(this);
      this.doneState = new DoneState(this);
      this.errorState = new ErrorState(this);
      this.currentState = this.signState;
    }

    init() {
      this.dom = document.createElement("div");
      this.dom.innerHTML =
        `<span>文件名称: ${this.fileName}</span><button data-action="button1">扫描中</button><button data-action="button2">删除</button>`;

      document.body.appendChild(this.dom);
      this.button1 = this.dom.querySelector('[data-action="button1"]');
      this.button2 = this.dom.querySelector('[data-action="button2"]');
      this.bindEvent();
    }

    bindEvent() {
      let self = this;
      this.button1.onclick = function () {
        self.currentState.clickHandler1();
      };

      this.button2.onclick = function () {
        self.currentState.clickHandler2();
      };
    }

    sign() {
      this.plugin.sign();
      this.currentState = this.signState;
    }

    uploading() {
      this.plugin.uploading();
      this.currentState = this.uploadingState;
    }

    pause() {
      this.button1.innerHTML = "已暂停，点击继续上传";
      this.plugin.pause();
      this.currentState = this.pauseState;
    }

    done() {
      this.button1.innerHTML = "上传完成";
      this.plugin.done();
      this.currentState = this.doneState;
    }

    error() {
      this.button1.innerHTML = "上传失败";
      this.currentState = this.errorState;
    }

    del() {
      this.plugin.del();
      this.dom.parentNode.removeChild(this.dom);
    }
  }

  class State {
    clickHandler1() {
      throw new Error("子类必须重写父类的clickHandler1方法");
    }

    clickHandler2() {
      throw new Error("子类必须重写父类的clickHandler2方法")
    }
  }

  let StateFactory = (param) => {
    class F extends State {
      constructor(uploadObj) {
        super();
        this.uploadObj = uploadObj;
      }
    }

    for (let i in param) {
      F.prototype[i] = param[i];
    }

    return F;
  }

  let SignState = StateFactory({
    clickHandler1: function () {
      console.log("扫描中，点击无效……");
    },
    clickHandler2: function () {
      console.log("文件正在上传，不能删除");
    }
  });

  let UploadingState = StateFactory({
    clickHandler1: function () {
      this.uploadObj.pause();
    },
    clickHandler2: function () {
      console.log("文件正在上传，不能删除");
    }
  })

  let PauseState = StateFactory({
    clickHandler1: function () {
      this.uploadObj.uploading();
    },
    clickHandler2: function () {
      this.uploadObj.del();
    }
  })

  let DoneState = StateFactory({
    clickHandler1: function () {
      console.log("文件已上传完成，点击无效");
    },
    clickHandler2: function () {
      this.uploadObj.del();
    }
  })

  let ErrorState = StateFactory({
    clickHandler1: function () {
      console.log("文件上传失败，点击无效");
    },
    clickHandler2: function () {
      this.uploadObj.del();
    }
  })


  /* 测试 */
  let uploadObj = new Upload("《hello world》");
  uploadObj.init();

  window.external.upload = function (state) {
    uploadObj[state]();
  }

  window.external.upload("sign");

  setTimeout(function () {
    window.external.upload("uploading");
  }, 1000);

  setTimeout(function () {
    window.external.upload("done");
  }, 5000);
</script>

</html>